#ifndef AVATAR
#define AVATAR

#include <cmath>
#include <vector>
#include <sstream>

#include <base\vec3f.h>
#include <base\vec2f.h>
#include <base\vec2i.h>
#include <base\vec2d.h>

#include <geo\geoLocation.h>
#include <geo\mercatorProjection.h>
#include <geo\inverseMercatorProjection.h>

#include <render\observers\moveObserver.h>
#include <render\observers\rotateObserver.h>
#include <app\states\viewingParametersState.h>
#include <app\states\moveState.h>

#include <boost/signal.hpp>
#include <boost/bind.hpp>

#define MAX_Z_ROTATE_STEP   45.0
#define MAX_X_ROTATE_STEP   45.0
#define MAX_X_ROTATE_ANGLE  90.0
#define MIN_X_ROTATE_ANGLE -90.0

#define MOVEMENT_SPEED 2000.0f

class avatar {

  vec3f view;        ///< line of sight vector
  vec3f up;          ///< up vector
  vec3f rotation;    ///< avatar current rotation
  vec3f translation; ///< avatar position with offset -start_tileLocation2d

  viewingParametersState *vpstate; ///< handler for view parameters state of current session

  vec2d tileLocation2d;
  vec2d start_tileLocation2d;

  float speed;

  float altitude;

  int base_level;

  boost::signal3<void, const float &, const float &, const float &> move_sig;
  boost::signal3<void, const float &, const float &, const float &> rotate_sig;

private:

  bool key_up;
  bool key_down;
  bool key_left;
  bool key_right;

public:

  void  setStartLocation(double lat, double lng, float altitude_, int level);
  vec2d getStartTileLocation2d(int level);

  void rotate(float x, float y, float z);
  void rotate(float dx, float dy);
  void applyRotation();

  void setSpeed(float movement_speed);

  void translate();
  void applyTranslation();
  vec3f getTranslation();

  float getAltitude();
  void changeAltitude(float diff);

  vec3f getRotation();
  vec3f getView(); // return view vector
  vec3f getUp();   // get up vector perpendicular to view vector

  vec2d getTileLocation2d(int level);
  vec2i getTileLocation2i(int level);
  geoLocation getGeoLocation();

  void addMoveObserver(moveObserver *ref);
  void addRotateObserver(rotateObserver *ref);

  avatar();
  ~avatar();

public:

  void key_up_pressed(bool pressed);
  void key_down_pressed(bool pressed);
  void key_left_pressed(bool pressed);
  void key_right_pressed(bool pressed);

  bool keyPressed();
};

#endif